package com.jaxb.binder;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * javax.xml.bind.JAXBContext.newInstance() is a very slow operation.
 * Cache more used context to improve the performance.
 * 
 * @author yyjiangc
 * @version 1.0 03/07/2011
 */
public class CachedStoneBinder extends AbstractStoneBinder implements BtStoneBinder {
	
	/**
	 * Maps used to cache the JAXBContext objects.
	 */
	private static final ConcurrentMap<String, JAXBContext> contexts = 
		new ConcurrentHashMap<String, JAXBContext>();

	/**
	 * Create a Marshaller object.
	 * 
	 * @param objFactoryClass the class object
	 * @return the Marshaller object created
	 * @throws JAXBException throws Exception if error occurs when create Marshaller.
	 */
	@Override
	public Marshaller createMarshaller(Class<?> objFactoryClass) 
        throws JAXBException {
		return createContext(objFactoryClass).createMarshaller();
	}

	/**
	 * Create a Unmarshaller object.
	 * 
	 * @param objFactoryClass the ObjectFactory class of the javabean.
	 * @return the Unmarshaller object created.
	 * @throws JAXBException throws Exception if error occurs when create Unmarshaller. 
	 */
	@Override
	public Unmarshaller createUnmarshaller(Class<?> objFactoryClass) 
	    throws JAXBException {
		return createContext(objFactoryClass).createUnmarshaller();
	}
	
	/**
	 * Create a JAXBContext object.
	 * 
	 * @param objFactoryClass the ObjectFactory class of the javabean.
	 * @return JAXBContext the JAXBContext object to the clazz object.
	 * @throws JAXBException throw JAXBException if error occurs. 
	 */
	private JAXBContext createContext(Class<?> objFactoryClass) throws JAXBException {
		String packageName = objFactoryClass.getPackage().getName();
		String contextKey = packageName + objFactoryClass.getName();
		
		JAXBContext context = contexts.get(contextKey);
		if (context == null) {
			try {
				context = JAXBContext.newInstance(objFactoryClass);
				contexts.put(contextKey, context);
			} catch (JAXBException e) {
				String msg = "Create JAXBcontext error.";
				throw e;
			}
		}
		return context;
	}
	
}
